package cn.exrick.xboot.common.qywxCode.Security;


import cn.exrick.xboot.common.constant.SecurityConstant;
import cn.exrick.xboot.common.qywxCode.Security.service.MyUserDetailsService;
import cn.exrick.xboot.common.utils.SpringContextUtil;
import cn.exrick.xboot.modules.base.entity.User;
import cn.exrick.xboot.modules.base.service.UserService;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 短信登陆鉴权 Provider，要求实现 AuthenticationProvider 接口
 */
@Component
@EnableTransactionManagement
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
    private UserDetailsService userDetailsService;
    @Autowired
    private  RedisTemplate  redisTemplate;
    @Autowired
    private UserService userService;

    @Resource
    private MyUserDetailsService myUserDetailsService;

    static Log log = LogFactory.get(SmsCodeAuthenticationProvider.class);

    public static SmsCodeAuthenticationProvider smsCodeAuthenticationProvider;

    @PostConstruct
    public void init(){
        smsCodeAuthenticationProvider = this;
    }

    //进行身份认证的逻辑
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
        //获取用户信息
        String str = null;
        String username = ((User) authenticationToken.getPrincipal()).getUsername();
        String pwd = ((User) authenticationToken.getPrincipal()).getPassword();
        String idcardEncryption = ((User) authenticationToken.getPrincipal()).getIdcardEncryption();
        UserDetails userDetails;
        User u = smsCodeAuthenticationProvider.userService.findByUsername(username);
        checkSmsCode(username);
        if (u == null){
            User shareSys = new User();
            shareSys.setUsername(username);
            //将加密后的身份证号放到pwd中带回
            shareSys.setPassword(pwd);
            shareSys.setIdcardEncryption(idcardEncryption);
            userDetails = smsCodeAuthenticationProvider.myUserDetailsService.loadUserByUsername(shareSys);
        }else {
            userDetails = userDetailsService.loadUserByUsername(username);
        }
        //调用自己写的 checkSmsCode() 方法，进行验证码校验，如果不合法，抛出 AuthenticationException 异常。

        // 此时鉴权成功后，应当重新 new 一个拥有鉴权的 authenticationResult 返回
        SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());

        authenticationResult.setDetails(authenticationToken.getDetails());

        return authenticationResult;
    }

    private void checkSmsCode(String username) {

        //获取用户输入的验证码 Code,,request.getParameter()-后台获取前台页面出传递过来的数据。
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String inputCode = request.getParameter("code");

        log.info("从登录表单中获取到的验证码" + inputCode);

        redisTemplate = (StringRedisTemplate) SpringContextUtil.getBean("stringRedisTemplate");
        String sendWxcode = (String) redisTemplate.opsForValue().get(SecurityConstant.USER_QYWX + username);
        if (inputCode == null || inputCode == "") {
            throw new BadCredentialsException("请输入验证码！");
        }
        if (sendWxcode == null){
            throw new BadCredentialsException("验证码已失效！");
        }
        if (!sendWxcode.equals(inputCode)){
            throw new BadCredentialsException("输入的验证码错误");
        }
        redisTemplate.delete(SecurityConstant.USER_QYWX + username);
        redisTemplate.delete(SecurityConstant.XBOOT_USER_CODE_EXPIRE + username);

    }
    @Override
    public boolean supports(Class<?> authentication) {
        // 判断 authentication 是不是 SmsCodeAuthenticationToken 的子类或子接口
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}
